﻿using Castle.DynamicProxy;
using Microsoft.Extensions.Logging;
using Net8.Project.Common;
using Net8.Project.Data.UnitOfWorks;
using System.Reflection;

namespace Net8.Project.Extension
{
    /// <summary>
    /// 事务拦截器，实现IInterceptor接口。
    /// 用于在方法调用前后自动管理事务。
    /// </summary>
    public class AOPTranInterceptor : IInterceptor
    {
        private readonly ILogger<AOPTranInterceptor> _logger;
        private readonly IUnitOfWorkManage _unitOfWorkManage;

        /// <summary>
        /// 构造函数，注入事务管理器和日志记录器。
        /// </summary>
        /// <param name="unitOfWorkManage">事务管理器</param>
        /// <param name="logger">日志记录器</param>
        public AOPTranInterceptor(IUnitOfWorkManage unitOfWorkManage, ILogger<AOPTranInterceptor> logger)
        {
            _unitOfWorkManage = unitOfWorkManage;
            _logger = logger;
        }

        /// <summary>
        /// 拦截方法调用，自动处理事务。
        /// </summary>
        /// <param name="invocation">包含被拦截方法的信息</param>
        public void Intercept(IInvocation invocation)
        {
            var method = invocation.MethodInvocationTarget ?? invocation.Method;
            // 检查方法是否标记了UseTranAttribute特性
            var tranAttr = method.GetCustomAttribute<UseTranAttribute>(true);
            if (tranAttr != null)
            {
                try
                {
                    // 方法调用前处理（开启事务）
                    Before(method, tranAttr.Propagation);

                    invocation.Proceed();

                    // 如果是异步方法，等待其完成
                    if (IsAsyncMethod(invocation.Method))
                    {
                        if (invocation.ReturnValue is Task task)
                        {
                            task.GetAwaiter().GetResult();
                        }
                    }

                    // 方法调用后处理（提交事务）
                    After(method);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "方法执行异常，事务回滚");
                    // 异常处理（回滚事务）
                    AfterException(method);
                    throw;
                }
            }
            else
            {
                // 未标记事务特性，直接执行
                invocation.Proceed();
            }
        }

        /// <summary>
        /// 方法调用前，根据事务传播机制开启事务。
        /// </summary>
        /// <param name="method">方法信息</param>
        /// <param name="propagation">事务传播机制</param>
        private void Before(MethodInfo method, Propagation propagation)
        {
            switch (propagation)
            {
                case Propagation.Required:
                    if (_unitOfWorkManage.TranCount <= 0)
                    {
                        _logger.LogDebug("Begin Transaction");
                        _unitOfWorkManage.BeginTran(method);
                    }
                    break;
                case Propagation.Mandatory:
                    if (_unitOfWorkManage.TranCount <= 0)
                    {
                        throw new InvalidOperationException("事务传播机制为Mandatory，但当前不存在事务。");
                    }
                    break;
                case Propagation.Nested:
                    _logger.LogDebug("Begin Nested Transaction");
                    _unitOfWorkManage.BeginTran(method);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(propagation), propagation, null);
            }
        }

        /// <summary>
        /// 方法调用后，提交事务。
        /// </summary>
        /// <param name="method">方法信息</param>
        private void After(MethodInfo method)
        {
            _unitOfWorkManage.CommitTran(method);
        }

        /// <summary>
        /// 方法调用异常时，回滚事务。
        /// </summary>
        /// <param name="method">方法信息</param>
        private void AfterException(MethodInfo method)
        {
            _unitOfWorkManage.RollbackTran(method);
        }

        /// <summary>
        /// 判断方法是否为异步方法。
        /// </summary>
        /// <param name="method">方法信息</param>
        /// <returns>是否为异步方法</returns>
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return method.ReturnType == typeof(Task) ||
                   (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>));
        }

        /// <summary>
        /// 获取类型的默认值。
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>默认值</returns>
        public object GetDefaultValue(Type type)
        {
            return type.IsValueType ? Activator.CreateInstance(type) : null;
        }
    }
}
